home *** CD-ROM | disk | FTP | other *** search
-
- COMMENT*--------------------------------------------------------
- This program will undelete files. To use, type UNDEL FILE.EXT or
- UNDEL DRIVE:FILE.EXT where DRIVE is A or B. For ASCII files use UNDEL/A
- FILE.EXT or UNDEL/A DRIVE:FILE.EXT; this prints out what is in each
- cluster before it adds it to the file and asks (Y/N) if it's correct.
- Only for use with DOS 2.0 and 2.10 double sided disks.
- ---------------------------------------------------------------*
- FCB_LOC EQU 5CH ;Location of FCB for deleted file in the PSP
- SWITCH_LOC EQU 81H ;Location of text typed after 'UNDEL'
- BIG_A EQU 412FH ;Test chars for /A
- SMALL_A EQU 612FH ;Test chars for /a
- CR EQU 13 ;ASCII carriage return
- LF EQU 10 ;ASCII line feed
- CODE_SEG SEGMENT
- ASSUME CS:CODE_SEG,DS:CODE_SEG,ES:CODE_SEG
- ORG 100H ;To make this a .com file
- ENTRY: JMP FIRST ;Skip over data area
-
- COPY_RIGHT DB '(C) 1984 S HOLZNER'
- I_O_FLAG DW ? ;Selects read or write of cluster
- START_CLUSTER DW ? ;Beginning cluster of deleted file
- FILE_SIZE DW ? ;File size in clusters (1 cluster=2 sectors)
- DISK_DRIVE DB 0 ;Drive of deleted file
- NOT_FOUND_MSG DB 13,'File not found deleted$' ;Messages
- WRITTEN_OVER_MSG DB 13,'File already written over$'
- IS_IT_MSG DB 13,10,'Is part of your file here? (Y/N) $'
-
- DATA DB 1024 DUP(0) ;Space for disk directory and FAT
- PROMPT_SECTOR DB 512 DUP(0) ;/A option uses for parts of file
-
- FIRST: ;Start the process
- UNDEL PROC NEAR
- MOV AL,CS:FCB_LOC ;Get the drive specified - 0 if none given
- SUB AL,1 ;Was it a 1 (A:) or 2 (B:)?
- JNC DRIVE_KNOWN ;Yes, store drive number
- MOV AH,19H ;No, get default drive from INT 21H
- INT 21H
- DRIVE_KNOWN:
- MOV DISK_DRIVE,AL ;Store drive
- MOV DX,3 ;Start to search dir, starts at sector 5
- LOOP: ADD DX,2 ;Add two to point at correct dir cluster
- CMP DX,11 ;Past end of directory?
- JB READ_DIR ;If not, read dir into data area
- MOV AH,9 ;Past end of dir & no match, exit with error
- LEA DX,NOT_FOUND_MSG
- INT 21H
- JMP OUT ;Exit
- READ_DIR:
- AND I_O_FLAG,0 ;Select read
- CALL CLUSTER_I_O ;Get two sectors into data area
- LEA DI,DATA ;Prepare to search for deleted entry
- MOV AL,0E5H ;DOS set first char of deleted entry to E5H
- MOV CX,400H ;Counter=1024 to search this entire dir cluster
- SEARCH: ;Look-for-next-deleted-entry loop
- REPNE SCASB
- JCXZ LOOP ;If no match (Counter=0), get next dir cluster
- MOV SI,FCB_LOC+2 ;Possible match, point to 2nd char of file name
- MOV BX,11 ;Compare all chars in name
- CMPLOOP:DEC BX ;Decrement the name comparison loop counter
- CMPS [DI],[SI] ;Compare dir entry and deleted file name
- JZ CMPLOOP ;If match, check next char
- CMP BX,0 ;Compare done, all chars matched perfectly?
- JNZ SEARCH ;No, keep checking through this dir cluster
- MOV AX,CS:FCB_LOC+1 ;Yes, get file's first letter
- MOV [DI-12],AX ;Move it into deleted entry (replace E5H)
-
- OR I_O_FLAG,1 ;Select a write of 1 cluster
- CALL CLUSTER_I_O ;Write directory with undeleted name to disk
- MOV AX,[DI+14] ;Get starting cluster to use in FAT
- MOV START_CLUSTER,AX ;Store it
- MOV AX,[DI+16] ;Get low word of file size (in bytes)
- TEST AX,1023 ;Find # of clusters - is MOD(size,1024)=0?
- JZ EVEN_K ;Yes, don't add 1 cluster before SHR
- ADD AX,1024 ;No, need another cluster
- EVEN_K: MOV CL,10 ;Divide by 1024 (=cluster size)
- SHR AX,CL
- MOV DX,[DI+18] ;High word of file size
- MOV CL,6 ;Multiply by 2^16=65536, divide by 2^10=1024
- SHL DX,CL
- ADD AX,DX ;Add high word clusters to low word clusters
- MOV FILE_SIZE,AX ;And store in FILE_SIZE
- MOV DX,1 ;Read in File Allocation Table (FAT)
- AND I_O_FLAG,0 ;Select a read of 1 cluster
- CALL CLUSTER_I_O
- MOV CX,FILE_SIZE ;Counter to loop over # of clusters
- MOV AX,START_CLUSTER ;Check if written over already
- DEC AX ;Move back one cluster from beginning of file
- CALL GET_NEXT_ZERO ;Is next empty space in FAT the START_CLUSTER?
- CMP DX,START_CLUSTER
- JE FILL ;Yes, OK to start filling FAT
- MOV AH,13H ;No, file written over
- MOV DX,FCB_LOC ;Delete restored dir entry; point to file name
- INT 21H ;And delete it
- MOV AH,9 ;Exit with error
- LEA DX,WRITTEN_OVER_MSG
- INT 21H
- JMP OUT ;So long
- FILL: MOV AX,DX ;Set old empty space in FAT to one just found
- MOV DX,0FFFH ;Assume this is last entry (FFFH=End of file)
- CMP CX,1 ;Is it the last entry? (CX=cluster counter)
- JZ LAST ;Yes, don't need to find next empty entry (zero)
- CALL GET_NEXT_ZERO ;Call with AX=old zero, returns DX=new zero
- LAST: CALL PUT_FAT_ENTRY ;Call with AX=old zero, DX=new zero, changes FAT
- LOOP FILL ;Work on next cluster
- MOV DX,1 ;Prepare to write new FAT, 1st copy
- OR I_O_FLAG,1 ;Select to write 1 cluster
- CALL CLUSTER_I_O ;Write the cluster
- MOV DX,3 ;Prepare to write new FAT, 2nd copy
- CALL CLUSTER_I_O
- OUT: INT 20H ;And leave
- UNDEL ENDP
-
- CLUSTER_I_O PROC NEAR ;Reads specified cluster (dir, FAT etc.)
- COMMENT* Put start sector in DX, loads Cluster into 'DATA' area*
- PUSH AX ;Save the used registers
- PUSH BX ;INT 25H destroys all reg.s
- PUSH CX
- PUSH DX
- PUSH DI
- MOV AL,DISK_DRIVE ;Get disk drive
- MOV CX,2 ;Request 2 sectors (1 cluster) to be read
- LEA BX,DATA ;Point to DATA area
- TEST I_O_FLAG,1
- JNZ WRITE
- INT 25H ;Read sector interrupt
- JMP POPOUT
- WRITE: INT 26H
- POPOUT: POPF ;Pop the extra push of flags
- POP DI ;Pop used (destroyed) registers
- POP DX
- POP CX
- POP BX
- POP AX
- RET ;Return
- CLUSTER_I_O ENDP
-
- GET_NEXT_ZERO PROC NEAR ;Unravel FAT and find next empty space in it
- COMMENT* FAT entry number (cluster #) in AX, returns next zero in DX*
- PUSH AX ;Push used reg.s
- PUSH BX
- PUSH CX
- CHECK_NEXT: ;Entry by entry loop
- INC AX ;AX is entry pointer, start with next entry
- MOV BX,AX ;Get 3/2*AX for actual offset into FAT
- SHL BX,1 ; (Since each entry is 1.5 bytes)
- ADD BX,AX
- SHR BX,1 ;BX has FAT offset value for entry # in AX
- MOV DX,WORD PTR DATA[BX] ;DX now has FAT entry's value
- TEST AX,1 ;Is the entry # even?
- JZ EVEN_ENTRY ;Yes, use bottom 12 bits
- MOV CL,4 ;No, use top 12 bits
- SHR DX,CL
- EVEN_ENTRY:
- AND DX,0FFFH ;Get bottom 12 bits (OK now for even or odd)
- CMP DX,0 ;Is the value for the given cluster # 0?
- JNE CHECK_NEXT ;No, look for next cluster
- MOV DX,AX ;Move entry value of zero into AX
- CMP AX,START_CLUSTER ;If this is the 1st one, skip /A option
- JE POPS
- MOV BX,SWITCH_LOC ;Was /A specified? Check data area in PSP
- MOV CX,[BX]
- CMP CX,SMALL_A ;Check for /a
- JE A_OPTION ;Yes, do /A
- CMP CX,BIG_A ;No, maybe a /A?
- JNE POPS ;No, leave.
- A_OPTION: ;/A was specified
- CALL PRINT_OUT ;Print out prompt sector
- JCXZ CHECK_NEXT ;If CX set to 0, sector wasn't right
- POPS: POP CX ;The pops before going
- POP BX
- POP AX
- RET
- GET_NEXT_ZERO ENDP
-
- PRINT_OUT PROC NEAR ;Print out a prompt sector
- COMMENT* Returns CX=1 if found the right sector, 0 otherwise *
- PUSH DX ;Push used reg
- ADD DX,DX ;Get 2*DX for sector number
- ADD DX,8 ;Add 8 to skip boot, FATs and dir
- MOV AL,DISK_DRIVE ;Get disk drive
- MOV CX,1 ;Ask for only 1 sector
- LEA BX,PROMPT_SECTOR ;Load into PROMPT_SECTOR area
- INT 25H ;Read the sector
- POPF ;Pop extra flags put on by INT 25H
- MOV AH,2 ;Prepare to print
- MOV DL,CR ;Send a carriage return
- INT 21H
- MOV DL,LF ;Send a line feed
- INT 21H
- MOV BX,0 ;Initialize char printout counter
- PRINT_LOOP: ;Like it says
- MOV DL,PROMPT_SECTOR[BX] ;Get char from read-in cluster
- INT 21H ;Print char
- INC BX ;Go on to next char
- CMP BX,160 ;Done 160 Chars yet?
- JBE PRINT_LOOP ;No; go back for more
- MOV AH,9 ;Yes, print Prompt message
- LEA DX,IS_IT_MSG
- INT 21H
- MOV AH,1 ;Get a char from keyboard
- INT 21H
- MOV CX,1 ;Assume found right sector (always optimistic)
- CMP AL,'Y' ;Was typed char a 'Y'?
- JE FOUND ;Yes, found right sector exit with CX still=0
- CMP AL,'y' ;No; was it a 'y'?
- JE FOUND ;Yes, leave with CX still = 0
- MOV CX,0 ;Not found, exit with CX=1
- FOUND: POP DX ;Pop destroyed DX reg
- RET
- PRINT_OUT ENDP
-
- PUT_FAT_ENTRY PROC NEAR ;Writes new FAT entry into FAT in DATA area
- COMMENT* Pass FAT cluster number in AX and new entry in DX*
- PUSH AX ;The requisite Pushes
- PUSH BX
- PUSH CX
- PUSH DX
- MOV BX,AX ;Get offset into FAT, 3*AX/2
- SHL BX,1 ;Multiply by 2
- ADD BX,AX ;Add AX to get 3*AX
- SHR BX,1 ;Divide by 2 -- BX has FAT offset value
- TEST AX,1 ;Do we have an even entry number?
- JZ P_EVEN_ENTRY ;Yes, use bottom 12 bits
- MOV CL,4 ;No, use top 12 bits
- SHL DX,CL
- P_EVEN_ENTRY:
- OR WORD PTR DATA[BX],DX ;Put Cluster # into FAT
- POP DX ;Do the Pops
- POP CX
- POP BX
- POP AX
- RET ;Return and you're done
- PUT_FAT_ENTRY ENDP
-
- CODE_SEG ENDS
- END ENTRY ;This sets the starting address to ENTRY
-
-
-
-
-
-
-
-
-
-
-